﻿namespace Moly.VB6
{
    using System;
    using System.Collections.Generic;
    using System.IO;

    public class VBPParser
    {
        public readonly string File;
        private readonly List<string> raw;
        public List<string> Dependencies;
        public List<string> SrcFiles;
        public VBPParser(string file)
        {
            SrcFiles = new List<string>();
            File = file;
            raw = new List<string>(System.IO.File.ReadAllLines(file));
            Dependencies = new List<string>();
            Dependencies.AddRange(raw.FindAll(IsDep));
            extarctSourceFiles();
        }

        private void extarctSourceFiles()
        {
            var keys = new[] { "Class", "Form", "Module", "UserControl", "PropertyPage", "Designer", "ResFile32" };
            foreach (var key in keys)
            {
                extractSrcKind(raw.FindAll(r => r.StartsWith(string.Format("{0}=", key))));
            }
        }

        private void extractSrcKind(List<string> kind)
        {
            kind.ForEach(extractPath);
        }

        private void extractPath(string line)
        {
            line = line.Substring(line.IndexOf("=") + 1);
            if (line.Contains(";"))
                line = line.Substring(line.IndexOf(";") + 1);

            line = line.Replace("\"", string.Empty).Trim().ToLower();
            line = Path.Combine(Path.GetDirectoryName(File), line);
            SrcFiles.Add(line);
        }

        private static bool IsDep(string line)
        {
            return line.StartsWith("Object=") || line.StartsWith("Reference=");
        }
        private int getLine(string key, out string full)
        {
            var all = raw.FindAll(d => d.StartsWith(key + "="));
            if (all.Count == 0)
            {
                throw new Exception(string.Format("Key {0} not found in {1}", key, File));
            }
            if (all.Count != 1)
                throw new Exception(string.Format("Key {0} Is Ambigus:{1}", key, string.Join("\n\t", all)));

            full = all[0];
            return raw.IndexOf(full);
        }
        public string GetUnique(string name)
        {
            string full;
            try
            {
                getLine(name, out full);
                return full.Substring(full.IndexOf("=") + 1).Replace("\"", string.Empty); ;
            }
            catch
            {
                var index = getLine("Startup", out full);
                raw.Insert(index + 1, name + "=");
                return string.Empty;
            }
        }
        public void UpdateDependency(int index, string line)
        {
            Dependencies[index] = line;
        }
        public void UpdateUnique(string key, object value)
        {
            GetUnique(key);// just to make sure the key gets created if missing.
            string full;
            var index = getLine(key, out full);
            raw.RemoveAt(index);
            if (full.EndsWith("\"") && !value.ToString().EndsWith("\""))
                value = string.Format("\"{0}\"", value);

            raw.Insert(index, string.Format("{0}={1}", key, value));
        }
        public void DropDependency(int index)
        {
            if (raw.Remove(Dependencies[index]))
                Dependencies.RemoveAt(index);
            else
            {
                throw new Exception("WTF");
            }
        }
        public void SaveCopy(string toCompile)
        {
            if (System.IO.File.Exists(toCompile))
                System.IO.File.SetAttributes(toCompile, FileAttributes.Normal);
            var stream = System.IO.File.Create(toCompile);
            var f = new StreamWriter(stream, System.Text.Encoding.GetEncoding(1256));
            var depIndex = 0;
            foreach (var line in raw)
            {
                if (IsDep(line))
                {
                    f.WriteLine(Dependencies[depIndex]);
                    depIndex++;
                    continue;
                }

                if (line.StartsWith("RelatedDoc")) // Remove related documents
                    continue;

                f.WriteLine(line);
            }
            f.Close();
        }
    }
}